package com.ccteam.fluidmusic.widget

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicBlur
import android.util.AttributeSet
import android.view.View
import android.view.animation.LinearInterpolator
import kotlin.math.max
import kotlin.math.roundToInt

/**
 * @author Xiaoc
 * @since 2021/3/1
 *
 * 流动背景自定义View
 * 该View需要一个Bitmap，然后会将其图像放大并拼装
 * 然后进行高斯模糊并播放旋转动画
 *
 * 由于会不断创建Bitmap，所以内存会攀升，但均会进行回收
 */
class FluidBackgroundView: View {

    /**
     * 背景饱和度滤镜
     */
    private lateinit var bitmapSaturation: ColorMatrix

    /**
     * 绘制背景封面的画笔
     */
    private lateinit var paintAlbumArtBitmap: Paint

    /**
     * 绘制背景颜色的画笔
     */
    private lateinit var paintBackgroundColor: Paint

    /**
     * 封面切换时的带透明度的开始画笔
     */
    private lateinit var paintAlbumArtChangeStart: Paint

    /**
     * 绘制整个背景用到的路径
     */
    private lateinit var pathBackground: Path

    /**
     * 封面切换时的带透明度的结束画笔
     */
    private lateinit var paintAlbumArtChangeEnd: Paint

    /**
     * 三种类型动画，分小 中 大三种市场
     */
    private lateinit var valueAnimatorSmall: ValueAnimator

    private lateinit var valueAnimatorMiddle: ValueAnimator

    private lateinit var valueAnimatorLarge: ValueAnimator

    /**
     * 背景要绘制封面的一个基准高度，用于创建一个基本的Bitmap副本
     */
    private var albumArtHeightBenchmark = 1

    /**
     * 背景要绘制封面的一个基准宽度，用于创建一个基本的Bitmap副本
     */
    private var albumArtWidthBenchmark = 1

    private var albumArtBaseVar = 1.0f

    private var albumArtBaseTransitionX = 1.0f

    private var albumArtBaseTransitionY = 1.0f

    private var albumArtBaseRotate = 1.0f

    /**
     * 最原始的Bitmap
     */
    private var albumOrigin: Bitmap? = null

    private var albumEffectShader: BitmapShader? = null

    private var albumBlank: Bitmap? = null

    /**
     * 底层背景默认颜色
     */
    private val colorBackground = arrayOf(Color.parseColor("#4D000000"),Color.parseColor("#1AFFFFFF"))

    /**
     * 背景封面变幻矩阵
     */
    private val matrixAlbumArtBitmap: Matrix = Matrix()

    private val scaleMatrix = Matrix().apply {
        setScale(baseScaleBenchMark, baseScaleBenchMark)
    }

    companion object{
        private const val baseScaleBenchMark = 25.0f
    }

    /**
     * 是否开启动画
     */
    private var enableAnimate = true

    constructor(context: Context): this(context,null)

    constructor(context: Context,attributeSet: AttributeSet?): this(context,attributeSet,0)

    constructor(context: Context,attributeSet: AttributeSet?,defStyleAttr: Int): super(context,attributeSet,defStyleAttr){
        // 设置硬件加速
        setLayerType(LAYER_TYPE_HARDWARE,null)

        initCanvas()

        initAnimator()

    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)

        albumArtWidthBenchmark = (w * 1.3f / baseScaleBenchMark).roundToInt()
        albumArtHeightBenchmark = (h * 1.3f / baseScaleBenchMark).roundToInt()

        albumArtBaseVar = max(albumArtHeightBenchmark,albumArtWidthBenchmark) * 1.3f
        albumArtBaseTransitionX = (-(albumArtBaseVar - albumArtWidthBenchmark)) / 2.0f
        albumArtBaseTransitionY = (-(albumArtBaseVar - albumArtHeightBenchmark)) / 2.0f
        albumArtBaseRotate = albumArtBaseVar / 2.0f

        pathBackground = Path().apply {
            addRect(0.0f,0.0f,w.toFloat(),h.toFloat(),Path.Direction.CW)
        }

        this.albumBlank = Bitmap.createBitmap(albumArtWidthBenchmark,albumArtHeightBenchmark, Bitmap.Config.ARGB_8888)
        updateAlbumArt(albumOrigin)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        if(this.albumOrigin?.isRecycled == true || this.albumOrigin == null){
            this.valueAnimatorSmall.cancel()
            this.valueAnimatorMiddle.cancel()
            this.valueAnimatorLarge.cancel()
            return
        }

        if(this.albumEffectShader == null
            || (this.valueAnimatorLarge.isStarted
            && !this.valueAnimatorLarge.isPaused)){

            var albumEffect = this.albumBlank!!

            // 绘制全屏叠加态封面
            val albumEffectCanvas = Canvas(albumEffect)
            val albumEffectScale1 = albumArtBaseVar / (this.albumOrigin?.height ?: 1)
            val animateValue1 = if(valueAnimatorLarge.isStarted){
                valueAnimatorLarge.animatedValue as Float
            } else {
                0.0f
            }

            matrixAlbumArtBitmap.setScale(albumEffectScale1,albumEffectScale1)
            matrixAlbumArtBitmap.postRotate(animateValue1,albumArtBaseRotate,albumArtBaseRotate)
            matrixAlbumArtBitmap.postTranslate(albumArtBaseTransitionX,albumArtBaseTransitionY)
            albumEffectCanvas.drawBitmap(this.albumOrigin!!,matrixAlbumArtBitmap,paintAlbumArtBitmap)

            val animateValue2 = if(valueAnimatorMiddle.isStarted){
                valueAnimatorMiddle.animatedValue as Float
            } else {
                0.0f
            }
            matrixAlbumArtBitmap.reset()
            matrixAlbumArtBitmap.setScale(albumEffectScale1,albumEffectScale1)
            matrixAlbumArtBitmap.postRotate(animateValue2,albumArtBaseRotate,albumArtBaseRotate)
            matrixAlbumArtBitmap.postTranslate(albumArtBaseTransitionX,albumArtBaseTransitionY)
            matrixAlbumArtBitmap.postTranslate(-0.95f * albumArtWidthBenchmark,-0.7f * albumArtHeightBenchmark)
            albumEffectCanvas.drawBitmap(this.albumOrigin!!,matrixAlbumArtBitmap,paintAlbumArtBitmap)

            val animateValue3 = if(valueAnimatorSmall.isStarted){
                valueAnimatorSmall.animatedValue as Float
            } else {
                0.0f
            }
            matrixAlbumArtBitmap.reset()
            matrixAlbumArtBitmap.setScale(albumEffectScale1,albumEffectScale1)
            matrixAlbumArtBitmap.postRotate(animateValue3,albumArtBaseRotate,albumArtBaseRotate)
            matrixAlbumArtBitmap.postTranslate(albumArtBaseTransitionX,albumArtBaseTransitionY)
            matrixAlbumArtBitmap.postTranslate(-0.5f * albumArtWidthBenchmark,0.7f * albumArtHeightBenchmark)
            matrixAlbumArtBitmap.postRotate(animateValue3,albumArtWidthBenchmark/2.0f,albumArtHeightBenchmark/2.0f)
            albumEffectCanvas.drawBitmap(this.albumOrigin!!,matrixAlbumArtBitmap,paintAlbumArtBitmap)

            /**
             * 绘制纯色背景
             */
            for(color in colorBackground){
                paintBackgroundColor.color = color
                albumEffectCanvas.drawPaint(paintBackgroundColor)
            }
            // 高斯模糊
            albumEffect = blurBitmap(albumEffect)
            val effectWith = albumEffect.width
            val effectHeight = albumEffect.height
            val matrix = Matrix(scaleMatrix)
            matrix.preTranslate((-(effectWith - (effectWith / 1.3f))) / 2.0f,(-(effectHeight - (effectHeight / 1.3f))) / 2.0f)
            // 设置未填充的部分为镜像填充
            val bitmapShader = BitmapShader(albumEffect,Shader.TileMode.MIRROR, Shader.TileMode.MIRROR)
            bitmapShader.setLocalMatrix(matrix)
            this.albumEffectShader = bitmapShader
            this.paintAlbumArtChangeEnd.shader = this.albumEffectShader
        }

        canvas.drawPath(this.pathBackground,this.paintAlbumArtChangeEnd)

        /**
         * 如果动画还没开始，设置其开始
         */
        if(!this.valueAnimatorLarge.isStarted){
            this.paintAlbumArtChangeStart.alpha = 255
            this.paintAlbumArtChangeEnd.alpha = 255
            this.valueAnimatorLarge.start()
            this.valueAnimatorMiddle.start()
            this.valueAnimatorSmall.start()
            invalidate()
        } else if(!this.valueAnimatorLarge.isPaused){
            postInvalidateDelayed(50)
        }
    }


    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        super.onVisibilityChanged(changedView, visibility)
        when(visibility){
            VISIBLE ->{
                resumeAnimate()
                invalidate()
            }
            INVISIBLE, GONE ->{
                pauseAnimate()
            }
        }
    }

    /**
     * 暂停动画
     */
    private fun pauseAnimate(){
        this.valueAnimatorSmall.pause()
        this.valueAnimatorMiddle.pause()
        this.valueAnimatorLarge.pause()
    }

    /**
     * 恢复动画
     */
    private fun resumeAnimate(){
        if(this.valueAnimatorLarge.isPaused){
            this.valueAnimatorSmall.resume()
            this.valueAnimatorMiddle.resume()
            this.valueAnimatorLarge.resume()
        }
    }

    /**
     * 更新专辑封面
     */
    fun updateAlbumArt(bitmap: Bitmap?){
        if(albumOrigin == bitmap || bitmap == null){
            return
        }

        this.albumOrigin = bitmap
        enableAnimate = true
        this.valueAnimatorSmall.cancel()
        this.valueAnimatorMiddle.cancel()
        this.valueAnimatorLarge.cancel()
        invalidate()
    }

    /**
     * 高斯模糊合成的Bitmap
     */
    private fun blurBitmap(bitmap: Bitmap): Bitmap{
        val outBitmap = Bitmap.createBitmap(bitmap.width,bitmap.height, Bitmap.Config.ARGB_8888)
        val rs = RenderScript.create(context)
        val blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs))
        val allIn = Allocation.createFromBitmap(rs,bitmap,Allocation.MipmapControl.MIPMAP_NONE,1)
        val allOut = Allocation.createFromBitmap(rs,outBitmap)
        blurScript.setRadius(23.0f)
        blurScript.setInput(allIn)
        blurScript.forEach(allOut)
        allOut.copyTo(outBitmap)
        rs.destroy()
        return outBitmap
    }

    /**
     * 初始化画布画笔等内容
     */
    private fun initCanvas(){
        bitmapSaturation = ColorMatrix().apply {
            // 设置背景饱和度滤镜
            setSaturation(2.5f)
        }

        paintAlbumArtBitmap = Paint(7).apply {
            // 将饱和度滤镜设置绘制背景封面的画笔中
            colorFilter = ColorMatrixColorFilter(bitmapSaturation)
        }

        paintBackgroundColor = Paint(7).apply {
            style = Paint.Style.FILL
        }

        paintAlbumArtChangeStart = Paint(7).apply {
            alpha = 255
        }
        paintAlbumArtChangeEnd = Paint(7).apply {
            alpha = 0
        }

    }

    /**
     * 初始化画笔等内容
     */
    private fun initAnimator(){
        val linearInterpolator = LinearInterpolator()
        valueAnimatorLarge = ValueAnimator.ofFloat(0.0f,-360.0f).apply {
            duration = 150000
            interpolator = linearInterpolator
            repeatCount = ValueAnimator.INFINITE
        }

        valueAnimatorMiddle = ValueAnimator.ofFloat(0.0f,360.0f).apply {
            duration = 140000
            interpolator = linearInterpolator
            repeatCount = ValueAnimator.INFINITE
        }

        valueAnimatorSmall = ValueAnimator.ofFloat(0.0f,360.0f).apply {
            duration = 120000
            interpolator = linearInterpolator
            repeatCount = ValueAnimator.INFINITE
        }


    }
}